package com.rs.command;

import com.rs.entity.basic.DeviceStatus;
import com.rs.entity.basic.MapDataPointVO;
import com.rs.entity.enums.*;
import com.rs.entity.task.Command;
import com.rs.entity.task.CommandAction;
import com.rs.entity.task.Target;
import com.rs.push.DevicePushMessage;
import com.rs.report.DetectionReport;
import com.rs.util.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;

/**
 * 接收到的指令缓存
 *
 * @author zhouwz
 * @date 2020/9/13 8:27
 */
@Log4j2
@Component
public class CommandBuffer {

    /**
     * 接收从队列来的任务记录
     *
     * @param vehicleCode 车辆编号
     * @param command     命令信息
     */
    public static void receive(String vehicleCode, Command command) {
        // 收到指令后车辆当前状态为执行中
        VehicleUtil.getCurrentStatus(vehicleCode).setStatus(VehicleStatus.EXECUTION.getCode());
        // 分析发送的指令
        commandAnalyse(vehicleCode, command);
    }

    /**
     * 对应车辆的当前指令执行处理(注意这里操作最终状态对象还是实时状态)
     *
     * @param vehicleCode 车辆编号
     */
    private static void commandAnalyse(String vehicleCode, Command command) {
        if (command != null) {
            // 执行指令
            doCommand(command, vehicleCode);
            // 回复收到指令
            DevicePushMessage.reportReceiveCommand2Rcs(command);
        }
    }

    /**
     * 执行指令
     *
     * @param command     指令
     * @param vehicleCode 车辆编号
     */
    private static void doCommand(Command command, String vehicleCode) {
        log.info("[命令解析] {} 开始解析命令:{} 动作有[{}]个", vehicleCode, CommandType.getCommandType(command.getCommandType()).getMsg(), command.getCommandList() != null ? command.getCommandList().size() : 0);
        switch (CommandEvent.getCommandEvent(command.getCommandType())) {
            case NORMAL:
                List<CommandAction> commandList = command.getCommandList();
                if (commandList != null) {
                    DeviceStatus currentStatus = VehicleUtil.getCurrentStatus(vehicleCode);
                    for (CommandAction action : commandList) {
                        switch (DeviceEvent.getDeviceEvent(action.getEventType())) {
                            case BACKWARD:
                                moveAction(vehicleCode, currentStatus, action);
                                // 打开倒车开关
                                BackTurnUtil.turnOn(vehicleCode);
                                break;
                            case FORWARD:
                                moveAction(vehicleCode, currentStatus, action);
                                // 关闭倒车开关
                                BackTurnUtil.turnOff(vehicleCode);
                                break;
                            case TURN:
                                currentStatus
                                        .setAngle(new BigDecimal(String.valueOf(action.getAngle())))
                                        .setShelfDirection(action.getShelfDirectionCode());
                                break;
                            case DROP:
                                // 下落后状态
                                currentStatus
                                        .setLiftStatus(LiftStatus.DROP.getCode())
                                        .setStatus(VehicleStatus.IDLE.getCode());
                                break;
                            case UP:
                                currentStatus
                                        .setLiftStatus(LiftStatus.UP.getCode())
                                        .setShelfDirection(action.getShelfDirectionCode());
                                break;
                            case DETECTION:
                                DetectionReport detectionReport = SpringContextHolder.getBean(DetectionReport.class);
                                detectionReport.generatorDetectionInfo(vehicleCode);
                                break;
                            case CHARGE:
                                MapDataPointVO chargeNode = NodeUtil.getChargeNode();
                                if (chargeNode != null) {
                                    VehicleUtil.putTarget(
                                            new Target(chargeNode.getXCoordinate(), chargeNode.getYCoordinate())
                                            , vehicleCode
                                    );
                                    // 打开倒车开关
                                    BackTurnUtil.turnOn(vehicleCode);
                                } else {
                                    log.error("没有充电点");
                                }
                                break;
                            case STOP_CHARGE:
                                VehicleUtil.idle(vehicleCode);
                            default:
                        }
                    }
                }
                break;
            case CANCEL:
            case SUSPEND:
                VehicleUtil.removeTarget(vehicleCode);
                VehicleUtil.idle(vehicleCode);
                break;
            default:
        }
    }

    /**
     * 移动动作赋值
     *
     * @param vehicleCode   车辆编号
     * @param currentStatus 当前状态
     * @param action        动作
     */
    private static void moveAction(String vehicleCode, DeviceStatus currentStatus, CommandAction action) {
        int lift = action.getLiftType() != null ? Integer.parseInt(action.getLiftType()) : LiftStatus.DROP.getCode();
        currentStatus
                .setLiftStatus(lift)
                .setShelfDirection(action.getShelfDirectionCode());
        // 根据方向计算途径的点
        calcThroughNodes(currentStatus, action);
        // 给最终目标点赋值
        VehicleUtil.putTarget(
                new Target(
                        NodeUtil.get(action.getNodeCode()).getXCoordinate(),
                        NodeUtil.get(action.getNodeCode()).getYCoordinate()
                )
                , vehicleCode
        );
    }

    /**
     * 计算途径的点位坐标集合
     *
     * @param currentStatus 当前状态
     * @param action        移动动作(包含目标X,Y坐标)
     */
    private static void calcThroughNodes(DeviceStatus currentStatus, CommandAction action) {
        BigDecimal targetX = NodeUtil.get(action.getNodeCode()).getXCoordinate();
        BigDecimal targetY = NodeUtil.get(action.getNodeCode()).getYCoordinate();
        String vehicleCode = currentStatus.getDeviceNo();
        BigDecimal currentY = currentStatus.getYCoordinate();
        BigDecimal currentX = currentStatus.getXCoordinate();
        switch (VehicleAngle.getVehicleAngle(currentStatus.getAngle().intValue())) {
            case UP:
                CoordinatorNodeUtil.upBetween(currentY, targetX, targetY, vehicleCode);
                break;
            case DOWN:
                CoordinatorNodeUtil.downBetween(currentY, targetX, targetY, vehicleCode);
                break;
            case LEFT:
                CoordinatorNodeUtil.leftBetween(currentX, targetX, targetY, vehicleCode);
                break;
            case RIGHT:
                CoordinatorNodeUtil.rightBetween(currentX, targetX, targetY, vehicleCode);
                break;
            default:
        }
    }
}
